package com.hemerasolutions.v2trainer.component.list;


import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.faces.context.FacesContext;


import javax.faces.event.ActionEvent;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.hemerasolutions.v2trainer.component.BaseComponent;
import com.hemerasolutions.v2trainer.component.interfaces.detail.StatisticDetailsCompInterface;
import com.hemerasolutions.v2trainer.component.interfaces.detail.StepCompInterface;
import com.hemerasolutions.v2trainer.component.interfaces.list.IntensityZoneListCompInterface;
import com.hemerasolutions.v2trainer.component.interfaces.list.ModalityIZListCompInterface;
import com.hemerasolutions.v2trainer.component.interfaces.list.StepListCompInterface;
import com.hemerasolutions.v2trainer.component.interfaces.table.StatisticTableCompInterface;
import com.hemerasolutions.v2trainer.dao.interfaces.TrainingTypeDaoInterface;
import com.hemerasolutions.v2trainer.model.exercise.Exercise;
import com.hemerasolutions.v2trainer.model.exerciseGroup.ExerciseGroup;
import com.hemerasolutions.v2trainer.model.library.Library;
import com.hemerasolutions.v2trainer.model.step.Step;
import com.hemerasolutions.v2trainer.model.training.TrainingStep;
import com.hemerasolutions.v2trainer.model.training.statistic.TrainingStatistic;



@Component("stepListComp")
@Scope("prototype")
public class StepListComp  extends BaseComponent  implements StepListCompInterface {


	private static final long serialVersionUID = 1L;
	
	private Step step;
	
	private int level;
	
	private List<TrainingStep> stepLevels;
	
	private TrainingStep stepLevel;
	
	private List<Library> librarys;
	
	private Map<Long,StepCompInterface> stepHandlers;
	
	private String translateList;

	private TrainingStatistic selStatistic;

	@Autowired
	private StatisticDetailsCompInterface statisticHandler;
	
	@Autowired
	private StatisticTableCompInterface statisticTable;
	
	@Autowired
	private IntensityZoneListCompInterface izHandler;
	
	@Autowired
	private ModalityIZListCompInterface imzHandler;
	
	@Autowired
	private transient ApplicationContext ctx;

	@Autowired
	private TrainingTypeDaoInterface ttDao;
	
	
	
	public StepListComp(){
		super();
	}

	@PostConstruct
	public void init(){
		super.init();
		
		this.setLibrarys(this.getActiveUserAllowedLibrarys());
	}
	
	@Override
	public void stepChanged(Step step) {
		this.translateList = this.readStepText();
		this.statisticTable.calcStatistics();
	}
		

	@Override
	public void copyLevel(ActionEvent ev){
		TrainingStep otherStepLevel = (TrainingStep)ev.getComponent().getAttributes().get("source");
		String panelToUpdate = (String)ev.getComponent().getAttributes().get("panelToUpdate");
		
		this.stepLevel.getRootStep().getSteps().clear();

		for(Step step:otherStepLevel.getRootStep().getSteps()){
			this.stepLevel.getRootStep().getSteps().add(new Step(stepLevel,step,this.stepLevel.getRootStep()));
		}
		
		this.updatePFComponnent(panelToUpdate);
	}
	


	@Override
	public void deleteChild(ActionEvent ev){
		Step step = (Step)ev.getComponent().getAttributes().get("step");
		Step parent = step.getParentStep();

		
		if(step.getSteps() != null && !step.getSteps().isEmpty()){
			this.deleteChildRecursive(step.getSteps());
		}
		
		parent.getSteps().remove(step);
		this.stepHandlers.remove(step.getUuid());

	}

	
	private void deleteChildRecursive(List<Step> steps){
		for(Step step:steps){
			if(step.getSteps() != null && !step.getSteps().isEmpty()){
				this.deleteChildRecursive(step.getSteps());
			}	
			this.stepHandlers.remove(step.getUuid());
		}
		steps.clear();
	}
	
    
	@Override
	public void addStep(ActionEvent ev){
    	int stepType   = Integer.parseInt((String)ev.getComponent().getAttributes().get("stepType"));

    	Step step = new Step(this.stepLevel,stepType,this.stepLevel.getRootStep());
    	this.stepLevel.getRootStep().getSteps().add(step);
    	this.step = step;
    	
		StepCompInterface stepHandler = ctx.getBean("stepComp",StepCompInterface.class);
		stepHandler.setStep(step);
		stepHandler.setParentPanelHandler(this);
		stepHandler.refresh();
		
		this.stepHandlers.put(step.getUuid(),stepHandler);
    }
    

    
	@Override
	public void addSteps(List<Step> steps){

    	for(Step step:steps){
    		this.stepLevel.getRootStep().getSteps().add(new Step(this.stepLevel,step,this.stepLevel.getRootStep()));
    	}
    	
    	this.recursiveBindStepHandler(this.stepLevel.getRootStep().getSteps());
    	
    	this.statisticTable.calcStatistics();
    }
    

	@Override
	public void trainingStepChanged(){
		Map<String,String> params = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();

		Long parentStep = Long.parseLong(params.get("parentStep"));
        Long childrenStep = Long.parseLong(  params.get("childrenStep"));
		Integer position =  Integer.parseInt(params.get("position"));

		Step step 		= this.findStepByUuid(this.stepLevel.getRootStep(), childrenStep);
		Step oldParent  = this.findStepByUuid(this.stepLevel.getRootStep(), step.getParentStep().getUuid());
		Step newParent  = this.findStepByUuid(this.stepLevel.getRootStep(), parentStep);
		
		if(	newParent.getType() == Step.EXERCISE_GROUP){
			if( step.getType() == Step.EXERCISE_STEP &&
				step.getExerciseStep().getExercise().getModality().equals(newParent.getExerciseGroupStep().getModality())){

				step.setParentStep(newParent);
				step.convertToGrouped();

				if(newParent.getSteps().isEmpty()){
					newParent.getSteps().add(step);
				}else{
					newParent.getSteps().add(position, step);
				}

				oldParent.getSteps().remove(step);
				
			}else if(step.getType() == Step.EXERCISE_GROUPED &&
				step.getExerciseStep().getExercise().getModality().equals(oldParent.getExerciseGroupStep().getModality())){
				step.setParentStep(newParent);

				if(newParent.getSteps().isEmpty()){
					newParent.getSteps().add(step);
				}else{
					newParent.getSteps().add(position, step);
				}

				oldParent.getSteps().remove(step);
				
			}else{
				this.showErrorMessage(this.localizedText("ErrorOnMove"), this.localizedText("InvalidDestination"));
			}
		}else{

			if(oldParent.getType() == Step.EXERCISE_GROUP){
				step.convertToUngrouped();
			}	
			
			oldParent.getSteps().remove(step);

			step.setParentStep(newParent);
			if(newParent.getSteps().isEmpty()){
				newParent.getSteps().add(step);
			}else{
				newParent.getSteps().add(position, step);
			}
		}

		this.stepHandlers.get(step.getUuid()).refresh();
		
		this.stepChanged(step);
		
	}
	
	
	private Step findStepByUuid(Step step, Long uuid){
		
		if(step.getUuid() == uuid){
			return step;
		}else{
			if(step.getSteps() != null && !step.getSteps().isEmpty() ){
				for(Step stepAux:step.getSteps()){
					Step returnStep = this.findStepByUuid(stepAux,uuid);
					if(returnStep != null){
						return returnStep;
					}
				}
			}else{
				return null;
			}
		}

		return null;
		
	}

	
	private String readStepText(){
		String desc = "";
		if(this.stepLevel.getRootStep().getSteps() != null){
			for(int x = 0; x < this.stepLevel.getRootStep().getSteps().size(); x++){
				Step step = this.stepLevel.getRootStep().getSteps().get(x);
				
				desc = desc + step.getStepTranslated();
				
				if(x != this.stepLevel.getRootStep().getSteps().size() - 1){
					desc = desc + ", ";
				}
			}
		}

		return desc;
		
	}
	
	@Override
	public String getTranslateList(){
		return translateList;
	}


	@Override
	public void setTranslateList(String translateList){
		this.translateList = translateList;
	}

	@Override
	public Step getStep() {
		return step;
	}

	@Override
	public void setStep(Step step) {
		this.step = step;
	}

	@Override
	public int getLevel() {
		return level;
	}

	@Override
	public void setLevel(int level) {
		this.level = level;
	}

	@Override
	public List<TrainingStep> getStepLevels() {
		return stepLevels;
	}

	@Override
	public void setStepLevels(List<TrainingStep> stepLevels) {
		this.stepLevels = stepLevels;
	}

	@Override
	public TrainingStep getStepLevel() {
		return stepLevel;
	}

	@Override
	public void setStepLevel(TrainingStep stepLevel) {
		this.stepLevel = stepLevel;
	}


	@Override
	public void refresh() {
		this.stepHandlers = new HashMap<Long,StepCompInterface>();
		
		this.level = this.stepLevel.getLevel();

		this.recursiveBindStepHandler(this.stepLevel.getRootStep().getSteps());

		this.statisticTable.setTrainingStep(this.stepLevel);
		this.statisticTable.setParentTrainingList(this);
		this.statisticTable.refresh();
		
	}

	private void recursiveBindStepHandler(List<Step> stepsAux) {
		for(Step step:stepsAux){

			StepCompInterface stepHandler = ctx.getBean("stepComp",StepCompInterface.class);
			stepHandler.setStep(step);
			stepHandler.setParentPanelHandler(this);
			stepHandler.refresh();
			
			this.stepHandlers.put(step.getUuid(),stepHandler);
			
			if(step.getSteps() != null && !step.getSteps().isEmpty()){
				this.recursiveBindStepHandler(step.getSteps());
			}
		}
	}
	
	@Override
	public List<Library> getLibrarys() {
		return librarys;
	}

	@Override
	public void setLibrarys(List<Library> librarys) {
		this.librarys = librarys;
	}

	@Override
	public Map<Long,StepCompInterface> getStepHandlers() {
		return stepHandlers;
	}

	@Override
	public void setStepHandlers(Map<Long,StepCompInterface> stepHandlers) {
		this.stepHandlers = stepHandlers;
	}

	@Override
	public void clearSteps() {
		this.stepLevel.getRootStep().getSteps().clear();
		this.stepHandlers.clear();
	}

	@Override
	public boolean addExerciseStep(Exercise exercise) {
		
		Step step = new Step(this.stepLevel,Step.EXERCISE_STEP,this.stepLevel.getRootStep());
		
		step.getExerciseStep().setExercise(exercise);

		this.stepLevel.getRootStep().getSteps().add(step);
		
		StepCompInterface stepHandler = ctx.getBean("stepComp",StepCompInterface.class);
		stepHandler.setStep(step);
		stepHandler.setParentPanelHandler(this);
		stepHandler.refresh();
		
		this.stepHandlers.put(step.getUuid(),stepHandler);
		
		return false;
	}

	@Override
	public void addStepGroup(String name, List<Step> steps) {
		Step group = new Step(this.stepLevel,Step.GROUP_OTHER,this.stepLevel.getRootStep());
		group.setName(name);
		this.step = group;

    	for(Step step:steps){
    		group.getSteps().add(new Step(this.stepLevel,step,group));
    	}

		StepCompInterface stepHandler = ctx.getBean("stepComp",StepCompInterface.class);
		stepHandler.setStep(step);
		stepHandler.setParentPanelHandler(this);
		stepHandler.refresh();
		
		this.stepHandlers.put(step.getUuid(),stepHandler);
    	
    	this.recursiveBindStepHandler(group.getSteps());

    	this.stepLevel.getRootStep().getSteps().add(group);
    	
	}


	@Override
	public void addExerciseGroup(ExerciseGroup exerciseGroup) {
		Step egStep = new Step(this.stepLevel,Step.EXERCISE_GROUP,this.stepLevel.getRootStep());
		
		
		egStep.setName(exerciseGroup.getName());
		egStep.getExerciseGroupStep().setModality(exerciseGroup.getModality());
		egStep.getExerciseGroupStep().setLevel(this.stepLevel.getLevel());

		this.step = egStep;
		
		for(Exercise exercise:exerciseGroup.getExercises()){
			Step exStep = new Step(this.stepLevel,Step.EXERCISE_GROUPED,egStep);

			exStep.getExerciseGroupedStep().setExercise(exercise);
			
			egStep.getSteps().add(exStep);
		}

		StepCompInterface stepHandler = ctx.getBean("stepComp",StepCompInterface.class);
		stepHandler.setStep(step);
		stepHandler.setParentPanelHandler(this);
		stepHandler.refresh();
		
		this.stepHandlers.put(step.getUuid(),stepHandler);
    	
    	this.recursiveBindStepHandler(egStep.getSteps());

    	this.stepLevel.getRootStep().getSteps().add(egStep);
		
	}
	
	@Override
	public TrainingTypeDaoInterface getTtDao() {
		return ttDao;
	}

	@Override
	public void setTtDao(TrainingTypeDaoInterface ttDao) {
		this.ttDao = ttDao;
	}


	@Override
	public IntensityZoneListCompInterface getIzHandler() {
		return izHandler;
	}


	@Override
	public void setIzHandler(IntensityZoneListCompInterface izHandler) {
		this.izHandler = izHandler;
	}


	@Override
	public ModalityIZListCompInterface getImzHandler() {
		return imzHandler;
	}


	@Override
	public void setImzHandler(ModalityIZListCompInterface imzHandler) {
		this.imzHandler = imzHandler;
	}


	@Override
	public StatisticTableCompInterface getStatisticTable() {
		return statisticTable;
	}


	@Override
	public void setStatisticTable(StatisticTableCompInterface statisticTable) {
		this.statisticTable = statisticTable;
	}

	@Override
	public TrainingStatistic getSelStatistic() {
		return selStatistic;
	}

	@Override
	public void setSelStatistic(TrainingStatistic selStatistic) {
		this.selStatistic = selStatistic;
	}

	@Override
	public StatisticDetailsCompInterface getStatisticHandler() {
		return statisticHandler;
	}

	@Override
	public void setStatisticHandler(StatisticDetailsCompInterface statisticHandler) {
		this.statisticHandler = statisticHandler;
	}

}
